package com.sprite.framework.entity;

import com.sprite.framework.common.Assert;
import com.sprite.framework.entity.config.EntityResourceInfo;
import com.sprite.framework.entity.model.EntityModelReader;
import com.sprite.framework.entity.model.ModelEntityUtil;
import com.sprite.framework.entity.script.EntityInsertScript;
import com.sprite.framework.entity.transaction.TransactionExecutor;
import com.sprite.framework.entity.transaction.TransactionScript;
import com.sprite.framework.entity.util.EntityDataReader;
import com.sprite.framework.entity.util.EntityGroup;
import com.sprite.utils.UtilCollection;
import com.sprite.utils.UtilString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.LinkedList;
import java.util.List;

/**
 * sprite orm 装载器，用于数据化数据库、载入数据初始数据
 * @author Jack
 */
public class EntityLoader {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private EntityScriptExecutor entityScriptExecutor;

    private String sqlType;

    /**
     * 1、装载实体模型，并同步给数据库
     * 2、装载实体数据
     * @see  #loadEntityModel(boolean)
     * @see  #loadEntityData()
     */
    public void load(){
       loadEntityModel(true);
       loadEntityData();
    }

    /**
     * 装载实体模型
     * @param updateDb 是否更新到数据库
     */
    public void loadEntityModel(boolean updateDb){
        Assert.notNull(sqlType,  "sqlType is not assign");
        Assert.notNull(entityScriptExecutor,  "entityScriptExecutor is not assign");

        try {

            // 加载EntityModel
            EntityModelReader entityModelReader = new EntityModelReader();
            for(EntityResourceInfo resource : EntityResourceInfo.getEntityModels()) {
                entityModelReader.buildModel(resource.getDocument());
            }

            entityModelReader.merge();

            if(UtilString.isBlank(sqlType)) {
                throw new Exception("not specified sql type ");

            }
            // 加载FieldType
            EntityResourceInfo resourceInfo = EntityResourceInfo.getFieldType(sqlType);
            if(resourceInfo == null) {
                throw new Exception("not found fieldTypeDef ： "+sqlType);
            }

            entityModelReader.buildModelFieldType(resourceInfo.getDocument(), sqlType);

            // 更新数据库结构
            if(updateDb){
                entityScriptExecutor.getDatabaseUtil().checkDb(ModelEntityUtil.getModelEntityList());
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 装载实体数据
     */
    public void loadEntityData(){
        Assert.notNull(sqlType,  "sqlType is not assign");
        Assert.notNull(entityScriptExecutor,  "entityScriptExecutor is not assign");

        try {
            // 装载初始化的数据
            List<EntityGroup> entityGroupList = new LinkedList<>();
            EntityDataReader dataReader = new EntityDataReader();
            for(EntityResourceInfo resource : EntityResourceInfo.getEntityDatas()) {
                dataReader.loadToEntity(resource.getDocument());
            }

            if(UtilCollection.isEmpty(entityGroupList)){
                return;
            }
            for(EntityGroup entityGroup : entityGroupList){
                try{
                    TransactionScript transactionScript = entityScriptExecutor.beginTransaction(true);
                    transactionScript.execute(new TransactionExecutor(){

                        @Override
                        public void execute() {
                            for(EntityObject entityObject : entityGroup.getEntities()){
                                EntityInsertScript insertScript = new EntityInsertScript(entityObject.getEntityName());
                                insertScript.addFields(entityObject);
                                entityScriptExecutor.execute(insertScript);
                            }
                        }
                    });
                }catch (Exception e){
                    logger.warn("[loader] load entity data error, ", e.getMessage());
                }

            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public String getSqlType() {
        return sqlType;
    }

    public void setSqlType(String sqlType) {
        this.sqlType = sqlType;
    }

    public EntityScriptExecutor getEntityScriptExecutor() {
        return entityScriptExecutor;
    }

    public void setEntityScriptExecutor(EntityScriptExecutor entityScriptExecutor) {
        this.entityScriptExecutor = entityScriptExecutor;
    }
}
